package com.seamtop.cuber.common.base;

import com.seamtop.cuber.common.conf.CuberConfiger;
import com.seamtop.cuber.common.entriy.*;
import com.seamtop.cuber.common.metadata.Column;
import com.seamtop.cuber.common.metadata.TableMetaData;
import com.seamtop.cuber.common.metadata.ValueTypeContants;
import com.seamtop.cuber.common.util.StringUtil;
import org.dom4j.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.crypto.Data;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;

/**
 * Created by zongjunfeng on 2015/8/11.
 */
public class DataObject {

    private static final Logger LOG = LoggerFactory.getLogger(DataObject.class);

    private static int CONST_CACHE_MINUTES = 0;

    private static long CONST_TIMESTAMP = new Date().getTime();

    private static String LOCAL_CONF_PATH = null;

    private static String CONF_MODULE = null;

    private static String REMOTE_CONF_PATH = null;

    private static HashMap<String,TableMetaData> metaDataMap = null;

    private static HashMap<String,TableOperatorBean> operatorDataMap = null;

    private static HashMap<String,CuberReducer> cuberReducerMap = null;

    private static HashMap<String,CuberReducer> cuberReducerIdMap = null;

    private static HashMap<String,CuberCounterSet> cuberCounterSetMap = null;

    private static HashMap<String,CuberCounter> cuberCounterMap = null;

    private static List<String> matchList = new ArrayList<String>();

    private static HashMap<Integer,TreeMap<Integer,List<CuberModule>>> cuberViewMap = new HashMap<Integer, TreeMap<Integer, List<CuberModule>>>();

    private static HashMap<String,Validator> cuberValidatorMap = new HashMap<String, Validator>();

    private static HashMap<String,String> confVersion = new HashMap<String, String>();


    private static HashMap<String,List<String>> menuRelationMap = new HashMap<String, List<String>>();

    private static HashMap<String,CuberMenu> cuberMenuMap = new HashMap<String, CuberMenu>();

    static {
        String confPath = CuberConfiger.clientConfigProperties.getProperty("conf.path");
        if(!StringUtil.isEmpty(confPath)){
            LOCAL_CONF_PATH = confPath;
        }
        String confCacheMinutes = CuberConfiger.clientConfigProperties.getProperty("conf.cache.mintes");
        if(!StringUtil.isEmpty(confCacheMinutes) && StringUtil.isDigital(confCacheMinutes)){
            CONST_CACHE_MINUTES = Integer.valueOf(confCacheMinutes);
        }

        String confModule = CuberConfiger.clientConfigProperties.getProperty("cuber.module");
        if(!StringUtil.isEmpty(confModule)){
            CONF_MODULE = confModule;
        }

        String confServer = CuberConfiger.clientConfigProperties.getProperty("cuber.conf.server");
        if(!StringUtil.isEmpty(confServer)){
            REMOTE_CONF_PATH = confServer;
        }
        if("web".equals(CONF_MODULE)){
            LOG.info("Cuber execute local init");
            localInit();
        }else{
            LOG.info("Cuber execute remote init");
            remoteInit();
        }
    }

    public static void init(ICuberInit cuberInit,String path){
        try{
            LOG.info("Load Cuber conf info[path:"+path+"]");
            Document counterDocument = cuberInit.loadCuberCounter(path);
            //load cuber counter set
            HashMap<String,CuberCounterSet> cuberCounterSetMap = ParseUtil.parseCounterSetDocument(counterDocument);
            LOG.info("Cuber Load Cuber Counter Set info:");
            for(String s:cuberCounterSetMap.keySet()){
                CuberCounterSet cuberCounterSet = cuberCounterSetMap.get(s);
                LOG.info("      counterSet:"+ cuberCounterSet.getId()  + " " +
                        " isTimeSettingEnable:"+cuberCounterSet.getCounterSettings().isTimeSettingEnable() + " timeStatPeriod:"+cuberCounterSet.getCounterSettings().getTimeStatPeriod() +
                        " isIntimeSettingEnable:"+cuberCounterSet.getCounterSettings().isInTimeSettingEnable()+" intimeResetPeriod:"+cuberCounterSet.getCounterSettings().getIntimeClearPeriod());
            }

            //load cuber counter
            HashMap<String,CuberCounter> cuberCounterMap = ParseUtil.parseCounterDocument(counterDocument,cuberCounterSetMap);
            LOG.info("Cuber Load Cuber Counter info:");
            for(String s:cuberCounterMap.keySet()){
                CuberCounter cuberCounter = cuberCounterMap.get(s);
                LOG.info("      counterId:"+cuberCounter.getCounterId() + " counterSet:"+ cuberCounter.getCounterSetId() +" counterName:"+cuberCounter.getCounterName() + " counterDesc:"+cuberCounter.getCounterDesc());
            }

            HashMap<String,TableMetaData> metaDataMap = new HashMap<String, TableMetaData>();
            //load truth table metadata
            Document t_document = cuberInit.loadTruthMData(path);
            HashMap<String,TableMetaData> truthMDataMap = ParseUtil.parseTruthTableMData(t_document);

            //load virtual table metadata
            Document vt_document = cuberInit.loadVirtualMData(path);
            HashMap<String,TableMetaData> virtualMDataMap = ParseUtil.parseVirtualTableMData(vt_document, truthMDataMap);
            //load counter table metadata
            HashMap<String,TableMetaData> counterMDataMap = ParseUtil.loadCounterMDataMap(cuberCounterMap);
            metaDataMap.putAll(truthMDataMap);
            metaDataMap.putAll(virtualMDataMap);
            metaDataMap.putAll(counterMDataMap);
            LOG.info("Cuber Load MetaData info:");
            for (String tableName : metaDataMap.keySet()) {
                TableMetaData metaData = metaDataMap.get(tableName);
                LOG.info("     tableId:" + metaData.getTableId() + " tableName:" + tableName + " isVirtualTable:"+metaData.isVirtualTable() + " primaryTable:"+metaData.getPrimaryTableName());
                if(!metaData.isVirtualTable()){
                    String keyType = ValueTypeContants.getKeyTypeDesc(metaData.getRowKey().getKeyType());
                    LOG.info("    rowKey[name:" + metaData.getRowKey().getKeyName() + " desc:" + metaData.getRowKey().getKeyDesc()
                            + " maxSize:" + metaData.getRowKey().getKeyMaxSize() + " type:" + keyType + "]");
                }
                HashMap<String, Column> columnMap = metaData.getColumnMap();
                for (String columnName : columnMap.keySet()) {
                    Column column = columnMap.get(columnName);
                    String columnType = "";
                    try {
                        columnType = ValueTypeContants.getKeyTypeDesc(column.getColumnType());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    LOG.info("    column[name:" + column.getColumnName() + " desc:" + column.getColumnDesc() + " maxSize:" + column.getColumnMaxSize()
                            + " type:" + columnType + " isJoinColumn:" + column.isJoinColumn() + " joinBy:" + column.getJoinBy() + " joinTable:" + column.getJoinTable()
                            + " isIncrement:" + column.isIncrement() + " match:"+ column.getMatch() +" columnType:"+columnType+"]");
                }
            }

            //load reducer
            Document reducerDocument = cuberInit.loadCuberReducer(path);
            HashMap<String,CuberReducer> cuberReducerMap = ParseUtil.parseCuberReducerDocument(reducerDocument);
            LOG.info("Cuber Load Cuber Reducer info:");
            for(String s:cuberReducerMap.keySet()){
                CuberReducer reducer = cuberReducerMap.get(s);
                LOG.info("      reducerId:" + reducer.getReducerId() + " statPeriod:" + reducer.getStatPeriod() + " statColumn:" + reducer.getStatColumn()
                        + " sourceTable:" + reducer.getSourceTable() + " outPutTable:" + reducer.getOutPutTable() + " where:" + reducer.getWhere() + " statType:" + reducer.getStatType());
            }

            HashMap<String,CuberReducer> cuberReducerIdMap = ParseUtil.parseCuberReducerIdDocument(reducerDocument);


            //load operator
            HashMap<String,TableOperatorBean> counterOperatorMap = ParseUtil.loadCounterOperateMap(cuberCounterMap);
            HashMap<String,TableOperatorBean> tableOperatorMap = ParseUtil.loadTableOperator(metaDataMap);
            HashMap<String,TableOperatorBean> operatorDataMap = new HashMap<String, TableOperatorBean>();
            operatorDataMap.putAll(counterOperatorMap);
            operatorDataMap.putAll(tableOperatorMap);
            LOG.info("Cuber Load Operator info:");
            for(String s:operatorDataMap.keySet()){
                TableOperatorBean operatorBean = operatorDataMap.get(s);
                LOG.info("    operator_name:" + operatorBean.getOperatorName() + " operator_table:" + operatorBean.getOperatorTable() +
                        " operator_type:" + operatorBean.getOperatorType());
            }

            DataObject.setMetaDataMap(metaDataMap);
            DataObject.setCuberCounterSetMap(cuberCounterSetMap);
            DataObject.setCuberReducerMap(cuberReducerMap);
            DataObject.setCuberReducerIdMap(cuberReducerIdMap);
            DataObject.setCuberCounterMap(cuberCounterMap);
            DataObject.setOperatorDataMap(operatorDataMap);
            LOG.info("Reload cuber conf info success");
        }catch (Exception e){
            LOG.error("Reload cuber conf info error", e);
        }
    }

    public static void localInit(){
        ICuberInit cuberInit = new CuberLocalInit();
        init(cuberInit,LOCAL_CONF_PATH);
    }

    public static void remoteInit(){
        ICuberInit cuberInit = new CuberRemoteInit();
        init(cuberInit,REMOTE_CONF_PATH);
    }

    public static HashMap<String, TableMetaData> getMetaDataMap() {
        long t1 = new Date().getTime();
        long t2 = CONST_TIMESTAMP;
        if(!"web".equals(CONF_MODULE) && !"client".equals(CONF_MODULE) && (CONST_CACHE_MINUTES > 0 && t1 - t2 > CONST_CACHE_MINUTES * 60 * 1000)){
            remoteInit();
        }
        return metaDataMap;
    }

    public synchronized static void setMetaDataMap(HashMap<String, TableMetaData> metaDataMap) {
        DataObject.metaDataMap = metaDataMap;
    }

    public static HashMap<String, TableOperatorBean> getOperatorDataMap() {
        long t1 = new Date().getTime();
        long t2 = CONST_TIMESTAMP;
        if(!"web".equals(CONF_MODULE) && !"client".equals(CONF_MODULE) && (CONST_CACHE_MINUTES > 0 && t1 - t2 > CONST_CACHE_MINUTES * 60 * 1000)){
            remoteInit();
        }
        return operatorDataMap;
    }

    public synchronized static void setOperatorDataMap(HashMap<String, TableOperatorBean> operatorDataMap) {
        DataObject.operatorDataMap = operatorDataMap;
    }

    public static HashMap<String, CuberReducer> getCuberReducerMap() {
        long t1 = new Date().getTime();
        long t2 = CONST_TIMESTAMP;
        if(!"web".equals(CONF_MODULE) && !"client".equals(CONF_MODULE) && (CONST_CACHE_MINUTES > 0 && t1 - t2 > CONST_CACHE_MINUTES * 60 * 1000)){
            remoteInit();
        }
        return cuberReducerMap;
    }

    public synchronized static void setCuberReducerMap(HashMap<String, CuberReducer> cuberReducerMap) {
        DataObject.cuberReducerMap = cuberReducerMap;
    }

    public static HashMap<String, CuberCounterSet> getCuberCounterSetMap() {
        long t1 = new Date().getTime();
        long t2 = CONST_TIMESTAMP;
        if(!"web".equals(CONF_MODULE) && !"client".equals(CONF_MODULE) && (CONST_CACHE_MINUTES > 0 && t1 - t2 > CONST_CACHE_MINUTES * 60 * 1000)){
            remoteInit();
        }
        return cuberCounterSetMap;
    }

    public synchronized static void setCuberCounterSetMap(HashMap<String, CuberCounterSet> cuberCounterSetMap) {
        DataObject.cuberCounterSetMap = cuberCounterSetMap;
    }

    public static HashMap<String, CuberCounter> getCuberCounterMap() {
        long t1 = new Date().getTime();
        long t2 = CONST_TIMESTAMP;
        if(!"web".equals(CONF_MODULE) && !"client".equals(CONF_MODULE) && (CONST_CACHE_MINUTES > 0 && t1 - t2 > CONST_CACHE_MINUTES * 60 * 1000)){
            remoteInit();
        }
        return cuberCounterMap;
    }

    public synchronized static void setCuberCounterMap(HashMap<String, CuberCounter> cuberCounterMap) {
        DataObject.cuberCounterMap = cuberCounterMap;
    }

    public static List<String> getMatchList() {
        return matchList;
    }

    public static void setMatchList(List<String> matchList) {
        DataObject.matchList = matchList;
    }

    public static HashMap<String, String> getConfVersion() {
        return confVersion;
    }

    public static void setConfVersion(HashMap<String, String> confVersion) {
        DataObject.confVersion = confVersion;
    }

    public static HashMap<String, List<String>> getMenuRelationMap() {
        return menuRelationMap;
    }

    public static void setMenuRelationMap(HashMap<String, List<String>> menuRelationMap) {
        DataObject.menuRelationMap = menuRelationMap;
    }

    public static HashMap<String, CuberMenu> getCuberMenuMap() {
        return cuberMenuMap;
    }

    public static void setCuberMenuMap(HashMap<String, CuberMenu> cuberMenuMap) {
        DataObject.cuberMenuMap = cuberMenuMap;
    }

    public static HashMap<Integer, TreeMap<Integer, List<CuberModule>>> getCuberViewMap() {
        return cuberViewMap;
    }

    public static void setCuberViewMap(HashMap<Integer, TreeMap<Integer, List<CuberModule>>> cuberViewMap) {
        DataObject.cuberViewMap = cuberViewMap;
    }

    public static HashMap<String, Validator> getCuberValidatorMap() {
        return cuberValidatorMap;
    }

    public static void setCuberValidatorMap(HashMap<String, Validator> cuberValidatorMap) {
        DataObject.cuberValidatorMap = cuberValidatorMap;
    }

    public static HashMap<String, CuberReducer> getCuberReducerIdMap() {
        return cuberReducerIdMap;
    }

    public static void setCuberReducerIdMap(HashMap<String, CuberReducer> cuberReducerIdMap) {
        DataObject.cuberReducerIdMap = cuberReducerIdMap;
    }
}
